<?php
/**
 * RoundCube antiBruteForce
 *
 * @version 1.0
 * @author Anderson J. de Souza
 * @url http://anderjs.blogspot.com
 */
class antiBruteForce extends rcube_plugin
{

	private $registers="logs/userlogins"; // arquivo de registro de tentativas
	private $attempts=3; // o numero de tentativas antes de bloquear o acesso;
	private $registeredAttemptsInTime=0; // variavel que mantem o numero de tentativas registradas dentro do tempo determinado
	private $time=600; // tempo entre tentativas
	private $blockedTime=null; // mantem o tempo restante de bloqueio em segundos
	private $message="<b>Acesso Bloqueado</b> Temporariamente "; // mensagem de erro de bloqueio

  function init()
  {
    $this->add_hook('startup', array($this, 'clearAuth'));
    $this->add_hook('template_object_loginform', array($this, 'blockMessage'));
    $this->add_hook('login_failed', array($this, 'logFail'));
  }

  function blocked() {
    // vaz contabilizacao caso nao haja bloqueio definido
    if ($this->blockedTime === null ) 
	$this->checkFails(); 
    return $this->blockedTime;
  }

  function clearAuth($args) {
    if ($this->blocked()) {
      $args['task']='login';
      $args['action']='';
     }
    return $args;
  }

  function getTrackIP(){
	 $trackIP = getenv('REMOTE_ADDR');
	 if (getenv('HTTP_X_FORWARDED_FOR'))
		 $trackIP.=','.getenv('HTTP_X_FORWARDED_FOR');
	 return $trackIP;
  }

  function checkFails() {
	  $track=$this->getTrackIP(); // caminho utilizado do acesso ip e ips de proxys
	  $time=$this->time; // tempo entre tentativas
	  $attempts=0; // registra o numero de tentativas dentro do tempo definido
	  $now=time(); // tempo de agora para calculos
	  $wait=0; // tempo entre as tentativas, mantem o time da ultima tentativa invalida

	  // le arquivo contabilizando as falhas de login dentro do tempo determinado
	  if (is_file($this->registers) && $fp=fopen($this->registers,'r')){
	  while ( $line=fgets($fp) ) {
		  if ( substr($line,0,strlen($track.":")) == $track.":" ) {
			  if ( ($wait = $now - substr($line,strlen($track.":"),10)) < $time )
				 $attempts++;
		  }
	  }
	  fclose($fp);
	  }

	// guarda valores para pesquisas futuras.
	if ($attempts >= $this->attempts) $this->blockedTime = ($time - $wait);
	$this->registeredAttemptsInTime = $attempts;
	return $attempts;
  }

  function blockMessage($args) {
	  if ($this->blocked()) 
		  $args['content']=$this->message.$this->blocked();
	  return $args;
  }


  function logFail($args)
  {
    if ($this->blocked()) return; // caso ja esteja bloqueado nao precisa registrar

    $log_entry = 'FAILED login for ' .$args['user']. ' from ' .getenv('REMOTE_ADDR'); 
    $log_config = rcmail::get_instance()->config->get('log_driver');
    
    error_log($this->getTrackIP().':'.time().':'.$args['user'].":[".date('d-M-Y H:i:s O')."]:$log_entry:"."\n", 3, $this->registers);
  }

}

?>
